package com.nervenets.web.controller.type;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nervenets.Global;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.controller.BaseController;
import com.nervenets.web.controller.IdParams;
import com.nervenets.web.entity.KeyValue;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.enumeration.Bank;
import com.nervenets.web.hibernate.dao.TypeDao;
import com.nervenets.web.hibernate.domain.Type;
import com.nervenets.web.redis.GlobalService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Api(value = "分类接口v1", description = "分类相关接口")
@RestController
@RequestMapping("/api/v1/type")
public class TypeController extends BaseController {
    @Resource
    private TypeDao typeDao;

    @ApiOperation("查看分类详情")
    @PostMapping("/detail")
    public String detail(@RequestBody IdParams params) {
        final Set<ConstraintViolation<IdParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        final Type object = typeDao.findById(params.getTargetId()).orElse(null);
        if (null == object) return errorMessage(MessageCode.code_404, "您查看的分类不存在");
        return successMessage(object);
    }

    @ApiOperation("分类新建或修改")
    @PostMapping("/edit")
    public String edit(@RequestBody TypeEditParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<TypeEditParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Type type = new Type();
        if (params.getTypeId() > 0) {
            type = typeDao.findById(params.getTypeId()).orElse(null);
            if (null == type) return errorMessage(MessageCode.code_404, "您修改的分类不存在");
        }
        type.setManagerId(params.getManagerId());
        type.setParentId(params.getParentId());
        type.setType(params.getType());
        type.setName(params.getName());
        type.setLogo(params.getLogo());
        type.setDetail(params.getDetail());
        type.setContent(params.getContent());
        type.setEnable(params.isEnable());
        type.setQueue(params.getQueue());
        type.setSystem(params.isSystem());
        typeDao.save(type);

        globalService.setGlobalPair(Global.Constants.TAGS_KEY, "");
        globalService.clearRedisTypeStored(type.getId());

        return successMessage(type);
    }

    @ApiOperation("分类列表")
    @PostMapping("/list")
    public String list(@RequestBody TypePagingParams params) {
        final Set<ConstraintViolation<TypePagingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        //Page<Type> page = typeDao.findAllByTypeAndParentIdAndManagerId(params.getType(), params.getParentId(), params.resolveUserId(), PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "queue")));
        Specification<Type> specification = (Specification<Type>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(criteriaBuilder.equal(root.get("removed"), 0));
            predicates.add(criteriaBuilder.equal(root.get("system"), params.isSystem()));
            if (null != params.getType()) {
                predicates.add(criteriaBuilder.equal(root.get("type"), params.getType()));
            }
            predicates.add(criteriaBuilder.equal(root.get("parentId"), params.getParentId()));
            if (!params.isSystem() && params.getManagerId() > 0) {
                predicates.add(criteriaBuilder.equal(root.get("managerId"), params.getManagerId()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Page<Type> page = typeDao.findAll(specification, PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "queue")));
        List<Type> list = new ArrayList<>();
        page.map(manager -> {
            list.add(manager);
            return manager;
        });
        return successMessage(list, new KeyValue("page", params.getPage()), new KeyValue("total", page.getTotalElements()));
    }

    @ApiOperation("所有系统分类的JS")
    @GetMapping(value = "/typesJS")
    public String types() throws Exception {
        String managerJson = globalService.getGlobalPair(Global.Constants.TAGS_KEY);
        if (!StringUtils.isEmpty(managerJson)) {
            return "var types = " + managerJson + ";";
        }
        List<Type> allTypes = typeDao.findAllBySystemIsTrueAndParentIdOrderByQueueDesc(0);
        JSONObject jsonObject = new JSONObject();
        for (Type type : allTypes) {
            if (type.isEnable()) {
                final TypeModel typeModel = new TypeModel(type);
                String tagType = type.getType().name();
                if (!jsonObject.containsKey(tagType)) {
                    jsonObject.put(tagType, new JSONArray());
                }
                List<Type> children = typeDao.findAllBySystemIsTrueAndParentIdOrderByQueueDesc(type.getId());
                for (Type child : children) {
                    final TypeModel childModel = new TypeModel(child);
                    if (child.isEnable()) typeModel.addChild(childModel);
                    jsonObject.put(String.valueOf(child.getId()), new TypeModel(child));
                }
                jsonObject.getJSONArray(tagType).add(typeModel);
            }
            jsonObject.put(String.valueOf(type.getId()), new TypeModel(type));
        }

        final String jsonString = jsonObject.toJSONString();
        globalService.setGlobalPair(Global.Constants.TAGS_KEY, jsonString);
        return "var types = " + jsonString + ";";
    }

    @ApiOperation("所有系统分类的JSON")
    @PostMapping("/typesJSON")
    public String typesJson() throws Exception {
        String managerJson = globalService.getGlobalPair(Global.Constants.TAGS_KEY);
        if (!StringUtils.isEmpty(managerJson)) {
            return managerJson;
        }
        List<Type> allTypes = typeDao.findAllBySystemIsTrueAndParentIdOrderByQueueDesc(0);
        JSONObject jsonObject = new JSONObject();
        for (Type type : allTypes) {
            if (type.isEnable()) {
                final TypeModel typeModel = new TypeModel(type);
                String tagType = type.getType().name();
                if (!jsonObject.containsKey(tagType)) {
                    jsonObject.put(tagType, new JSONArray());
                }
                List<Type> children = typeDao.findAllBySystemIsTrueAndParentIdOrderByQueueDesc(type.getId());
                for (Type child : children) {
                    final TypeModel childModel = new TypeModel(child);
                    if (child.isEnable()) typeModel.addChild(childModel);
                    jsonObject.put(String.valueOf(child.getId()), new TypeModel(child));
                }
                jsonObject.getJSONArray(tagType).add(typeModel);
            }
            jsonObject.put(String.valueOf(type.getId()), new TypeModel(type));
        }

        String result = jsonObject.toJSONString();
        globalService.setGlobalPair(Global.Constants.TAGS_KEY, result);
        return result;
    }

    @ApiOperation("所有银行列表")
    @PostMapping("/banks")
    public String banks() {
        return successMessage(Bank.values());
    }
}
